package kobetool.dshowwrapper;

import java.nio.ByteBuffer;

/**
 * Class for Video Subtype
 * @see GUID#GUID(String)
 */
public class GUID {

    public final static GUID RGB24 = new GUID(
            "0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70");

    public final static GUID RGB32 = new GUID(
            "0xe436eb7e, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70");

    public final static GUID IYUV = new GUID(
            "0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71");

    public final static GUID I420 = new GUID(
            "0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71");

    public final static GUID YUYV = new GUID(
            "0x56595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71");

    private ByteBuffer buf;

    public GUID(String fmt) {
        fmt = fmt.replaceAll("0x", "").replaceAll(",", "").replaceAll("\\s", "");
        if(fmt.length()!=32) throw new IllegalArgumentException();
        buf = ByteBuffer.allocateDirect(16);
        int[] lens = new int[] {4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1};
        for(int i=0, j=0; ; ) {
            int len = lens[j];
            for(int k=0; k<len; k++) {
                int p = (len-k-1 + i)*2;
                try {
                    buf.put(Integer.valueOf(fmt.substring(p, p+2), 16).byteValue());
                } catch (NumberFormatException e) {
                    throw e;
                }
            }
            i += len;
            if(++j==lens.length) break;
        }
    }

    /**
     * Parameter must be DirectByteBuffer
     * @param buf
     * @see java.nio.ByteBuffer#allocateDirect(int)
     */
    public GUID(ByteBuffer buf) {
        if(buf==null || !buf.isDirect()) throw new IllegalArgumentException();
        this.buf = buf;
    }

    public ByteBuffer getBuf() {
        return buf.asReadOnlyBuffer();
    }

    public String getFourcc() {
        byte[] bytes = new byte[4];
        for(int i=0; i<4; i++) {
            bytes[i] = buf.get(i);
        }
        return new String(bytes);
    }

    private void appendHex(StringBuilder sb, int start, int len) {
        sb.append("0x");
        for(int i=len-1; i>=0; i--) {
            String hs = Integer.toHexString(0xff&buf.get(start+i));
            if(hs.length()==1) sb.append("0");
            sb.append(hs);
        }
    }

    public String toString() {
        StringBuilder sb = new StringBuilder("(" + getFourcc() + ")");
        int[] lens = new int[] {4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1};
        for(int i=0, j=0; ;) {
            int len = lens[j];
            appendHex(sb, i, len);
            if(++j != lens.length) sb.append(", ");
            else break;
            i += len;
        }
        return sb.toString();
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        GUID guid = (GUID) o;

        if(buf.capacity()!=guid.buf.capacity()) return false;

        for(int i=0; i<buf.capacity(); i++) {
            if(buf.get(i)!=guid.buf.get(i)) return false;
        }

        return true;
    }

    public int hashCode() {
        return buf.hashCode();
    }
}
